package com.cloud.canal.mes;

import com.alibaba.fastjson.JSON;
import com.alibaba.otter.canal.protocol.CanalEntry;
import com.cloud.canal.CanalDataHandler;
import com.cloud.factory.ServiceInterface;
import com.cloud.factory.SqlTableAnnotation;
import com.cloud.mapper.CanalUserMapper;
import com.cloud.service.ExceptionLogService;
import com.cloud.canal.CanalDataHandler;
import com.cloud.entity.UserEntity;
import com.cloud.factory.ServiceInterface;
import com.cloud.factory.SqlTableAnnotation;
import com.cloud.mapper.CanalUserMapper;
import com.cloud.service.ExceptionLogService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.Objects;


@SqlTableAnnotation(tableName = "user")
@Component
@Slf4j
public class UserHandler implements ServiceInterface {

    @Autowired
    private CanalUserMapper canalUserMapper;
    @Autowired
    private ExceptionLogService exceptionLogService;

    @Override
    public void execute(List<CanalEntry.Column> columns, String type, String tableName) {
        UserEntity user = CanalDataHandler.convertToBean(columns, UserEntity.class);
        if ("insert".equals(type) && Objects.nonNull(user)) {
            try {
                Integer result = canalUserMapper.insertUser(user);
                if (result < 1) {
                    //插入异常表
                    exceptionLogService.insertExceptionLog(user, "insert", tableName, null);
                }
            } catch (Exception e) {
                //todo 出现异常需要，将数据写入表里，定时任务或者人为处理
                //插入异常表
                exceptionLogService.insertExceptionLog(user, "insert", tableName, JSON.toJSONString(e.getStackTrace()));
            }
        }
        //更新使用更新时间作为乐观锁，解决多节点canal先更新覆盖后更新数据，导致数据不准确

        if ("update".equals(type) && Objects.nonNull(user)) {
            try {
                // todo 通过分片策略与主键更新数据
                if (StringUtils.isEmpty(user.getId())) {
                    log.info("canal更新操作未执行,传递的数据主键或者分片策略不存在,表名:{},数据:{}",tableName, user);
                    return;
                }
                Integer result = canalUserMapper.updateUser(user);
                if (result < 1) {
                    //插入异常表
                    //多节点部署时，该表插入两种情况
                    //①先取到了更新的语句，后来insert才过来，定时任务处理
                    //②先更新的数据后收到，导致老数据覆盖新数据，乐观锁-更新时间
                    exceptionLogService.insertExceptionLog(user, "update", tableName, null);
                }

            } catch (Exception e) {
                //todo 出现异常需要，将数据写入表里，定时任务或者人为处理
                //插入异常表
                exceptionLogService.insertExceptionLog(user, "update", tableName, JSON.toJSONString(e.getStackTrace()));
            }
        }
        if ("delete".equals(type) && Objects.nonNull(user)) {
            try {
                // todo 通过分片策略与主键删除数据,一定要找到分片策略和主键匹配删除
                if (StringUtils.isEmpty(user.getId())) {
                    log.info("canal删除操作未执行,传递的数据主键或者分片策略不存在,表名:{},数据:{}", tableName, user);
                    return;
                }
                Integer result = canalUserMapper.deleteUser(user);
                if (result < 1) {
                    //插入异常表
                    exceptionLogService.insertExceptionLog(user, "delete", tableName, null);
                }
            } catch (Exception e) {
                //todo 出现异常需要，将数据写入表里，定时任务或者人为处理
                //插入异常表
                exceptionLogService.insertExceptionLog(user, "delete", tableName, JSON.toJSONString(e.getStackTrace()));
            }
        }
    }
}
